/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package model;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import util.Utilities;
        

/**
 *
 * @author Asus
 */
public class RevisionController {
    
    private ArrayList<FileInfo> fileInfos;
    private int version;
    
    public RevisionController(){
        fileInfos = new ArrayList<FileInfo>();
    }
    
    public RevisionController(RevisionController _RevisionController){
        fileInfos = new ArrayList<FileInfo>();
        for(int i=0;i<_RevisionController.getFileInfos().size();i++){
            fileInfos.add(new FileInfo(_RevisionController.getFileInfos().get(i)));
        }
    }

    public static RevisionController getVersionControl(String folderPath) {
        RevisionController result = new RevisionController();
        String protocolFolder = folderPath + "/.rrm";
        File protocolFile = new File(protocolFolder);
        
        if (!protocolFile.exists() || !protocolFile.isDirectory())
            protocolFile.mkdirs();
        String[] revList    = protocolFile.list();

       // if (revList == null) {
          if (revList.length == 0){
            // create new revision folder
            result.version = 1;
            result.evaluateFolder(folderPath);
        } else {
            // evaluate existing
            String lastRev      = revList[revList.length - 1];
            result.version     = Integer.parseInt(lastRev.substring(0, lastRev.indexOf(".")));

            try {
                ArrayList<FileInfo> currentFileInfo = FileInfo.readFileInfos(protocolFolder + "/" + lastRev);
                result.evaluateFolder(folderPath);

                // Searching match file infos
                for (int i = 0; i < result.fileInfos.size(); ++i) {
                    int found = -1;

                    FileInfo current = result.fileInfos.get(i);
                    for (int j = 0; j < currentFileInfo.size(); ++j){
                        if (currentFileInfo.get(j).getFilePath().equals(current.getFilePath()) && currentFileInfo.get(j).getFileType() != Utilities.TYPE_DELETED) {
                            found = j;
                            break;
                        }
                    }

                    //not found (doesn't exist), skip
                    if (found == -1) continue;

                    //exist, checking revision
                    FileInfo prev = currentFileInfo.get(found);

                    System.out.println("[Revision control] prev = " + prev.getFilePath() + " " + prev.getFileCheckSum());
                    System.out.println("[Revision control] current = " + current.getFilePath() + " " + current.getFileCheckSum());

                    if (prev.getFileCheckSum().equals(current.getFileCheckSum())) {
                        //match, set revision
                        current.setVersion(prev.getVersion());
                    } else {
                        //not match, different revision
                        current.setVersion(prev.getVersion() + 1);
                    }
                }

                // mencari file yang perlu didelete
                for (int i = 0; i < currentFileInfo.size(); ++i) {
                    int found = -1;
                    
                    FileInfo current = currentFileInfo.get(i);
                    for (int j = 0; j < result.fileInfos.size(); ++j) {
                        //not comparing the deleted file
                        if (currentFileInfo.get(j).getFilePath().equals(current.getFilePath()) && current.getFileType() != Utilities.TYPE_DELETED) {
                            found = j;
                            break;
                        }
                    }

                    //found deleted file and controlled, skip
                    if (found != -1) continue;

                    //File need to be deleted, added to FileInfo list as deleted.
                    current.setFileType(Utilities.TYPE_DELETED);
                    result.fileInfos.add(current);
                }
            } catch (IOException iEx) {
                
            }
        }

        System.out.println("[Revision Control] generating revision control success");

        return result;
    }
    
    public void setRevisionToFile(String folderPath, boolean newVersion){
        File file = new File(folderPath + "/.rrm");

        if (file.exists()) {
            String revList[] = file.list();

            if (revList.length == 0) {
                // create new revision folder
                version = 1;
            } else {
                // evaluate existing
                String lastRev  = revList[revList.length - 1];
                version        = Integer.parseInt(lastRev.substring(0, lastRev.indexOf(".")));
            }
        }
        
        int version = this.version;

        if (newVersion)
            ++version;

        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(folderPath + "/.rrm/" + version + ".rhs"));

            int metadataCount = fileInfos.size();

            bos.write((byte)((metadataCount >> 24) % 256));
            bos.write((byte)((metadataCount >> 16) % 256));
            bos.write((byte)((metadataCount >> 8) % 256));
            bos.write((byte)(metadataCount % 256));

            for (int i = 0; i < metadataCount; ++i)
                fileInfos.get(i).writeFileInfo(bos);

            bos.close();
        } catch (IOException iEx) {
            
        }
    }
    
    public void evaluateFolder(String folderPath) {
        File file = new File(folderPath);
        String[] fileList = file.list();

        for (int i = 0; i < fileList.length; ++i) {
            if (fileList[i].equals(".rrm")) continue;
            String filePath = folderPath + "/" + fileList[i];
            fileInfos.add(FileInfo.createFileInfo(filePath));
            File newFile = new File(filePath);
            if (newFile.isDirectory())
                evaluateFolder(filePath);

        }
    }
    
    public ArrayList<FileInfo> getFileInfos() {
        return fileInfos;
    }

    public void setFileInfos(ArrayList<FileInfo> fileInfos) {
        this.fileInfos = fileInfos;
    }

    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }
    
    public static RevisionController createFromByte(byte[] data) {
        RevisionController result = new RevisionController();
        result.setFileInfos(FileInfo.readFileInfos(data));

        return result;
    }
    
    public byte[] toSend() {
        int fileinfoCount = fileInfos.size();
        StringBuilder sb = new StringBuilder();

        sb.append((char)((fileinfoCount >> 24) % 256));
        sb.append((char)((fileinfoCount >> 16) % 256));
        sb.append((char)((fileinfoCount >> 8) % 256));
        sb.append((char)(fileinfoCount % 256));

        for (int i = 0; i < fileinfoCount; ++i) {
            byte[] toSend = fileInfos.get(i).toSend();

            for (int j = 0; j < toSend.length; ++j)
                sb.append((char)toSend[j]);
        }

        String str = sb.toString();
        byte[] result = new byte[str.length()];

        for (int i = 0; i < result.length; ++i)
            result[i] = (byte)str.charAt(i);

        return result;
    }
}
